import sys
sys.path.insert(0,'/home/yjj/xquant/')
sys.path.insert(0,'/opt/xquant/')
import time
import datetime
import queue
import threading
import math
import pandas as pd
import numpy as np
from event import BarEvent
from collections import deque
from initclass import InitClass

class HistoryBarData(InitClass):
    #核心类，是框架的灵魂，会把所有的其他类的方法整合到里面，
    # 使得整个逻辑变得更加清楚
    def __init__(self,InitClass_instance):
        self.asset=InitClass_instance.asset
        self.home_currency=InitClass_instance.home_currency
        self.money=InitClass_instance.money
        self.max_len=InitClass_instance.max_len
        self.events=InitClass_instance.events
        self.all_pair_name=InitClass_instance.all_pair_name
        self.data_root=InitClass_instance.data_root
        self.time_frame=InitClass_instance.time_frame
        self.trade_pairs=InitClass_instance.trade_pairs
        self.continue_backtest=InitClass_instance.continue_backtest
        self.leverage=InitClass_instance.leverage
        self.backtest=InitClass_instance.backtest
        self.pairs=self.get_trade_assist_pairs()
        self.data_name=[pair+'__'+str(frame)+'M' for frame in self.time_frame for pair in self.pairs ]
        self.symbol_data={}
        self.datas = {  pair:{'time':deque(maxlen=self.max_len),
                            'open':deque(maxlen=self.max_len),
                            'high':deque(maxlen=self.max_len),
                            'low':deque(maxlen=self.max_len),
                            'close':deque(maxlen=self.max_len),
                            'volume':deque(maxlen=self.max_len)}
                        for pair in self.data_name
                    }
        #用于存储多周期的时候，未来的数据
        self.cache_data={pair:None for pair in self.data_name}
        #用来存储当前的时间
        self.now_time=None

    def add_history_data(self):
        #trade_pairs是需要加载的货币的名字,list
        #time_frame是需要加载的时间周期,list
        comb_index_dict={time_frame:None for time_frame in self.time_frame}
        #comb_index = None
        for time_frame in self.time_frame:
            path=self.data_root+'oanda_'+str(time_frame)+'M/'
            data_name=[pair+'__'+str(time_frame)+'M'  for pair in self.pairs ]
            for i in data_name:
                df2=pd.read_csv(path+i.split('__')[0]+'.csv',index_col=0)
                #print(type(df2))
                self.symbol_data[i]=df2
                if  comb_index_dict[time_frame] is None:
                    comb_index_dict[time_frame] = df2.index
                else:
                    comb_index_dict[time_frame].union(df2.index)
            #print(self.symbol_data.keys())
            for pair in self.symbol_data.keys():
                if str(time_frame) in pair:
                    self.symbol_data[pair] = self.symbol_data[pair].reindex(index=sorted(comb_index_dict[time_frame])).iterrows()
        #pannel= pd.Panel(self.symbol_data)
        #self.symbol_data={}
        #for data_name ,df in pannel.iteritems():
            #df.fillna(method='ffill', inplace=True)
            #self.symbol_data[data_name]=df.iterrows()

        self._to_queue()
    def _get_new_bar(self,name):
        """
        Returns the latest bar from the data feed as a tuple of
        (sybmbol, datetime, open, low, high, close, volume).
        """
        #print(name)
        #print(self.symbol_data)
        for b in self.symbol_data[name]:
            #print(self.symbol_data[name])
            #print(b)
            yield tuple([name, datetime.datetime.strptime(b[0], '%Y-%m-%d %H:%M:%S'),
                        b[1][0], b[1][1], b[1][2], b[1][3], b[1][4]])

    def _to_queue(self):
        #print(self.symbol_data)
        """
        Pushes the latest bar to the latest_symbol_data structure
        for all symbols in the symbol list.
        """
        for i in range(len(self.data_name)):
            pair=self.data_name[i]
            if i==0:
                try:
                    bar = self._get_new_bar(pair).__next__()
                except StopIteration:
                    self.continue_backtest = False
                    print('回测数据结束')
                else:
                    if bar is not None:
                        self.now_time=str(bar[1])
                        #如果收盘价不是nan
                        #print('bar',bar)
                        #assert  math.isnan(bar[5]),'出现空值'
                        if  math.isnan(bar[5]):
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['high'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['low'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['close'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['volume'].append(0)
                            tev=BarEvent(bar[0],str(bar[1]),
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                0)
                        else:
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(bar[2])
                            self.datas[pair]['high'].append(bar[3])
                            self.datas[pair]['low'].append(bar[4])
                            self.datas[pair]['close'].append(bar[5])
                            self.datas[pair]['volume'].append(bar[6])
                            tev=BarEvent(bar[0], str(bar[1]),bar[2],
                                        bar[3],bar[4],bar[5],bar[6])
                        #print(bar[0], str(bar[1]),bar[2],bar[3],bar[4],bar[5],bar[6])
                        #print(tev)
                        self.events.put(tev)
            #在中间
            if i>0 and i<len(self.data_name)-1:
                if self.cache_data[pair] is None:
                    try:
                        bar = self._get_new_bar(pair).__next__()
                    except StopIteration:
                        self.continue_backtest = False
                        print('回测数据结束')
                    else:
                        if bar is not None:
                            #如果当前bar的时间小于等于当前的交易时间，那么，就加如
                            bar_time=str(bar[1])
                            #如果当前bar的时间小于等于交易的时间
                            if bar_time<=self.now_time:
                                #如果收盘价不是nan
                                #print('bar',bar)
                                #assert  math.isnan(bar[5]),'出现空值'
                                if  math.isnan(bar[5]):
                                    self.datas[pair]['time'].append(str(bar[1]))
                                    self.datas[pair]['open'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['high'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['low'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['close'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['volume'].append(0)
                                    tev=BarEvent(bar[0],str(bar[1]),
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        0)
                                else:
                                    self.datas[pair]['time'].append(str(bar[1]))
                                    self.datas[pair]['open'].append(bar[2])
                                    self.datas[pair]['high'].append(bar[3])
                                    self.datas[pair]['low'].append(bar[4])
                                    self.datas[pair]['close'].append(bar[5])
                                    self.datas[pair]['volume'].append(bar[6])
                                    tev=BarEvent(bar[0], str(bar[1]),bar[2],
                                                bar[3],bar[4],bar[5],bar[6])
                                #print(bar[0], str(bar[1]),bar[2],bar[3],bar[4],bar[5],bar[6])
                                #print(tev)
                                self.events.put(tev)
                            #如果大于交易时间，就加入到缓存中
                            if bar_time>self.now_time:
                                self.cache_data[pair]=bar
                #如果缓存中的数据不是None的话，就判断当前缓存的数据是否加入到bar_event中
                if self.cache_data[pair] is not None:
                    bar=self.cache_data[pair]
                    bar_time=str(bar[1])
                    #如果ｂａｒ时间小于等于交易时间的话,加入到bar_event中
                    if bar_time<=self.now_time:
                        self.cache_data[pair]=None
                        if  math.isnan(bar[5]):
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['high'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['low'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['close'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['volume'].append(0)
                            tev=BarEvent(bar[0],str(bar[1]),
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                0)
                        else:
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(bar[2])
                            self.datas[pair]['high'].append(bar[3])
                            self.datas[pair]['low'].append(bar[4])
                            self.datas[pair]['close'].append(bar[5])
                            self.datas[pair]['volume'].append(bar[6])
                            tev=BarEvent(bar[0], str(bar[1]),bar[2],
                                        bar[3],bar[4],bar[5],bar[6])
                        #print(bar[0], str(bar[1]),bar[2],bar[3],bar[4],bar[5],bar[6])
                        #print(tev)
                        self.events.put(tev)
                    #如果bar的时间大于交易时间，那么，就需要进一步等待
                    if bar_time>self.now_time:
                        pass
            if i==len(self.data_name)-1:
                if self.cache_data[pair] is None:
                    try:
                        bar = self._get_new_bar(pair).__next__()
                    except StopIteration:
                        self.continue_backtest = False
                        print('回测数据结束')
                    else:
                        if bar is not None:
                            #如果当前bar的时间小于等于当前的交易时间，那么，就加如
                            bar_time=str(bar[1])
                            #如果当前bar的时间小于等于交易的时间
                            if bar_time<=self.now_time:
                                #如果收盘价不是nan
                                #print('bar',bar)
                                #assert  math.isnan(bar[5]),'出现空值'
                                if  math.isnan(bar[5]):
                                    self.datas[pair]['time'].append(str(bar[1]))
                                    self.datas[pair]['open'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['high'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['low'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['close'].append(self.datas[pair]['close'][-1])
                                    self.datas[pair]['volume'].append(0)
                                    tev=BarEvent(bar[0],str(bar[1]),
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        self.datas[pair]['close'][-1],
                                        0)
                                else:
                                    self.datas[pair]['time'].append(str(bar[1]))
                                    self.datas[pair]['open'].append(bar[2])
                                    self.datas[pair]['high'].append(bar[3])
                                    self.datas[pair]['low'].append(bar[4])
                                    self.datas[pair]['close'].append(bar[5])
                                    self.datas[pair]['volume'].append(bar[6])
                                    tev=BarEvent(bar[0], str(bar[1]),bar[2],
                                                bar[3],bar[4],bar[5],bar[6])
                                #print(bar[0], str(bar[1]),bar[2],bar[3],bar[4],bar[5],bar[6])
                                #print(tev)
                                self.events.put(tev)
                            #如果大于交易时间，就加入到缓存中
                            if bar_time>self.now_time:
                                self.cache_data[pair]=bar
                #如果缓存中的数据不是None的话，就判断当前缓存的数据是否加入到bar_event中
                if self.cache_data[pair] is not None:
                    bar=self.cache_data[pair]
                    bar_time=str(bar[1])
                    #如果ｂａｒ时间小于等于交易时间的话,加入到bar_event中
                    if bar_time<=self.now_time:
                        self.cache_data[pair]=None
                        if  math.isnan(bar[5]):
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['high'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['low'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['close'].append(self.datas[pair]['close'][-1])
                            self.datas[pair]['volume'].append(0)
                            tev=BarEvent(bar[0],str(bar[1]),
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                self.datas[pair]['close'][-1],
                                0)
                        else:
                            self.datas[pair]['time'].append(str(bar[1]))
                            self.datas[pair]['open'].append(bar[2])
                            self.datas[pair]['high'].append(bar[3])
                            self.datas[pair]['low'].append(bar[4])
                            self.datas[pair]['close'].append(bar[5])
                            self.datas[pair]['volume'].append(bar[6])
                            tev=BarEvent(bar[0], str(bar[1]),bar[2],
                                        bar[3],bar[4],bar[5],bar[6])
                        #print(bar[0], str(bar[1]),bar[2],bar[3],bar[4],bar[5],bar[6])
                        #print(tev)
                        self.events.put(tev)
                    #如果bar的时间大于交易时间，那么，就需要进一步等待
                    if bar_time>self.now_time:
                        pass
                self.now_time=None







    def get_trade_assist_pairs(self):
        # 获取要交易的货币和辅助货币
        #print(self)
        if  self.asset=='currency':
            trade_assist_pairs = self.trade_pairs + self.get_assist_pairs()
            pairs=trade_assist_pairs
        else:
            pairs=pairs
        return pairs

    def get_assist_pairs(self):
        #　获取货币的辅助货币
        pair_list=[]
        for pair in self.trade_pairs:
            quote_currency=pair.split('_')[0]
            base_currency=pair.split('_')[1]
            if quote_currency==self.home_currency:
                pass
            elif base_currency==self.home_currency:
                pass
            else:
                # quote_currency
                if quote_currency+'_'+self.home_currency in self.all_pair_name:
                    pair_list.append(quote_currency+'_'+self.home_currency)
                elif self.home_currency+'_'+quote_currency in self.all_pair_name:
                    pair_list.append(self.home_currency+'_'+quote_currency)
                else:
                    print('辅助货币出现问题')
                # base_currency
                if base_currency+'_'+self.home_currency in self.all_pair_name:
                    pair_list.append(base_currency+'_'+self.home_currency)
                elif self.home_currency+'_'+base_currency in self.all_pair_name:
                    pair_list.append(self.home_currency+'_'+base_currency)
                else:
                    print('辅助货币出现问题')
        return pair_list
